package com.cmy.web.widget

import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.Context
import android.graphics.Bitmap
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.webkit.*
import android.widget.FrameLayout
import android.widget.ProgressBar
import androidx.annotation.AttrRes
import com.cmy.web.WebViewState
import com.cmy.web.databinding.ViewWebBinding
import com.cmy.web.listener.*
import com.cmy.web.listener.JavascriptInterface

/**
 * @name:
 *  BaseWebView
 * @package:
 *  com.cmy.web.widget
 * @date:
 *  2023/4/2310:39
 * @author
 *    cmy
 * @description
 *  对应于Android系统的webView的封装类
 **/
class BaseWebView constructor(context: Context, attrs: AttributeSet?, @AttrRes defStyleAttr:Int): FrameLayout(context,attrs,defStyleAttr),
    WebViewLifecycleListener, BaseWebViewListener, BaseWebViewExpandListener {
    constructor(context: Context, attrs: AttributeSet?):this(context,attrs,0)
    constructor(context: Context):this(context,null)
    private val binding by lazy {   ViewWebBinding.inflate(LayoutInflater.from(context)) }

    private val mWebView by lazy { binding.webView }

    protected var isLoadError = false

    private var mWebViewClient :BaseWebClient? = null

    private var mWebChromeClient : BaseWebChromeClient?=null

    private var mJsDialogListener : JsDialogListener? = null

    private var mInterceptListener: BaseViewInterceptListener? = null

    private var mJavascriptInterface : JavascriptInterface? = null

    private var mStateListener:WebViewStateListener? = null
    init {
        addView(binding.root)
        initWebView()
    }

    /**
     * 初始化
     */
    @SuppressLint("SuspiciousIndentation", "SetJavaScriptEnabled", "JavascriptInterface")
    protected open fun initWebView() {
        //------------------------
        mWebView.clearCache(true)
        mWebView.setLayerType(LAYER_TYPE_NONE, null)
        val webSettings: WebSettings = mWebView.settings
//        if (NetworkUtils.isConnected(getApplicationContext())) {
//            //根据cache-control决定是否从网络上取数据。
//            webSettings.cacheMode = WebSettings.LOAD_DEFAULT
//        } else {
//            //没网，则从本地获取，即离线加载
//            webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
//        }

        WebView.setWebContentsDebuggingEnabled(false)


//        webSettings.setDomStorageEnabled(true);
//
//        webSettings.setAppCacheMaxSize(1024*1024*8);
//
//        String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
//
//        webSettings.setAppCachePath(appCachePath);
//
//        webSettings.setAllowFileAccess(true);

        webSettings.domStorageEnabled = true
        webSettings.databaseEnabled = true
//        webSettings.setAppCacheEnabled(true)
        webSettings.useWideViewPort = true
        webSettings.setGeolocationEnabled(true)
        webSettings.loadWithOverviewMode = true
        webSettings.allowFileAccess = false
        webSettings.setSupportZoom(false)
        webSettings.builtInZoomControls = false
//        webSettings.allowFileAccessFromFileURLs = true
//        webSettings.allowUniversalAccessFromFileURLs = true
        webSettings.mediaPlaybackRequiresUserGesture = false
        //        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);//支持内容重新布局
        webSettings.mixedContentMode = WebSettings.LOAD_DEFAULT
        mWebView.settings.defaultTextEncodingName = "gb2312"
        mWebViewClient = BaseWebClient(binding.pbLoading)
        mWebChromeClient = BaseWebChromeClient(binding.pbLoading)
        mWebView.webChromeClient = mWebChromeClient
        mWebView.webViewClient = mWebViewClient as BaseWebClient
//        mWebView.setDefaultHandler(DefaultHandler())
        mWebView.overScrollMode = OVER_SCROLL_NEVER
//        mWebView.setBackgroundColor(ContextCompat.getColor(context, R.color.background))
//        val ua = webSettings.userAgentString


//        //获取密码接口
//        mWebView.getHttpAuthUsernamePassword(host, realm)
//        //保存密码接口
//        mWebView.setHttpAuthUsernamePassword(String host, String realm,String username, String password)



        if (mJavascriptInterface != null){
            mWebView.addJavascriptInterface(mJavascriptInterface!!.getInterfaceClass(), mJavascriptInterface!!.getInterfaceName())
            webSettings.javaScriptEnabled = true
        }else{
            webSettings.javaScriptEnabled = false
        }

        //可以关闭定位功能，内核默认是开启的
        webSettings.setGeolocationEnabled(false)
        Log.e("TAG", "UA:" + webSettings.userAgentString)
        mWebView.clearFocus()

    }



    inner class BaseWebClient(loading: ProgressBar) :WebViewClient(){
        private val pbLoading = loading
        override fun shouldOverrideUrlLoading(
            view: android.webkit.WebView?,
            url: String?
        ): Boolean {
            return if (mInterceptListener != null){
                mInterceptListener!!.shouldOverrideUrlLoading(url)
            }else{
                super.shouldOverrideUrlLoading(view, url)
            }
        }


        override fun shouldOverrideUrlLoading(
            view:WebView?,
            request: WebResourceRequest?
        ): Boolean {
            return if (mInterceptListener != null){
                mInterceptListener!!.shouldOverrideUrlLoading(request?.url.toString())
            }else{
                super.shouldOverrideUrlLoading(view, request)
            }
        }


        override fun onPageFinished(view: WebView, url: String?) {
            super.onPageFinished(view, url)
            pbLoading.visibility = GONE
            pbLoading.progress = 0

            if (mStateListener != null){
                mStateListener!!.onState(if (isLoadError) WebViewState.LoadError else WebViewState.LoadComplete)
            }

        }

        override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
            super.onPageStarted(view, url, favicon)
            pbLoading.visibility = VISIBLE
            if (mStateListener != null){
                mStateListener!!.onState(WebViewState.Loading)
            }
        }

        // 旧版本，会在新版本中也可能被调用，所以加上一个判断，防止重复显示
        override fun onReceivedError(
            view:WebView?,
            errorCode: Int,
            description: String?,
            failingUrl: String?
        ) {
            super.onReceivedError(view, errorCode, description, failingUrl)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                return
            }
            // 在这里显示自定义错误页
            isLoadError = true

        }

        // 新版本，只会在Android6及以上调用
        @TargetApi(Build.VERSION_CODES.M)
        override fun onReceivedError(
            view: WebView?,
            request: WebResourceRequest,
            error: WebResourceError?
        ) {
            super.onReceivedError(view, request, error)
            if (request.isForMainFrame) { // 或者： if(request.getUrl().toString() .equals(getUrl()))
                // 在这里显示自定义错误页
                isLoadError = true
            }
        }

    }


    inner class BaseWebChromeClient(loading: ProgressBar) :WebChromeClient(){
        private val pbLoading: ProgressBar = loading

        override fun onJsAlert(webview: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
            //TODO  可以弹框或进行其它处理，但一定要回调result.confirm或者cancel 这里要返回true否则内核会进行提示
            return if (mJsDialogListener != null){
                mJsDialogListener!!.onJsAlert(url,message)
            }else{
                super.onJsAlert(webview, url,message, result)
            }
        }

        override fun onJsConfirm(webview: WebView?, url: String?, message: String?, result: JsResult?): Boolean{
            //TODO 可以弹框或进行其它处理，但一定要回调result.confirm或者cancel
            return if (mJsDialogListener != null){
                mJsDialogListener!!.onJsConfirm(url,message)
            }else{
                super.onJsConfirm(webview, url,message, result)
            }
        }


        override fun onJsBeforeUnload(webview: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
            //TODO 可以弹框或进行其它处理，但一定要回调result.confirm或者cancel
            return if (mJsDialogListener != null){
                mJsDialogListener!!.onJsBeforeUnload(url,message)
            }else{
                super.onJsBeforeUnload(webview, url,message, result)
            }
        }

        override fun onJsPrompt(
            webview: WebView?,
            url: String?,
            message: String?,
            defaultvalue: String?,
            result: JsPromptResult?
        ): Boolean {
            //TODO 可以弹框或进行其它处理，但一定要回调result.confirm或者cancel，confirm可以将用户输入作为参数
            return if (mJsDialogListener != null){
                mJsDialogListener!!.onJsPrompt(url,message,defaultvalue)
            }else{
                super.onJsPrompt(webview, url, message, defaultvalue, result)
            }
        }

        override fun onProgressChanged(view: WebView?, newProgress: Int) {
            super.onProgressChanged(view, newProgress)
            if (newProgress < 100){
                pbLoading.progress = newProgress
                if (mStateListener != null){
                    mStateListener!!.onState(WebViewState.Loading)
                }
            }
        }
    }


    //--------------------------公共调用-----------------------------------


    /**
     * 返回对应的WebView视图，便于拓展
     */
    fun getWebView():WebView{
        return mWebView
    }




    //------------------------实现各类生命周期类----------------------------

    override fun addJsDialogListener(jsDialogListener: JsDialogListener) {
        this.mJsDialogListener = jsDialogListener
    }

    override fun addInterceptListener(interceptListener: BaseViewInterceptListener) {
       this.mInterceptListener = interceptListener
    }

    override fun addJavascriptInterface(javascriptInterface: JavascriptInterface) {
        this.mJavascriptInterface = javascriptInterface
    }

    override fun registerWebViewStateListener(stateListener: WebViewStateListener) {
        this.mStateListener = stateListener
    }
    override fun loadUrl(url: String) {
        mWebView.loadUrl(url)
    }

    override fun loadDataWithBaseURL(
        baseUrl: String,
        data: String,
        mimeType: String,
        encoding: String,
        failUrl: String
    ) {
      mWebView.loadDataWithBaseURL(baseUrl,data,mimeType,encoding,failUrl)
    }

    override fun evaluateJavascript(script: String, result: (String?) -> Unit) {
       mWebView.evaluateJavascript(script,result)
    }

    override fun evaluateJavascript(script: String, resultCallback: CallBackFunction) {
       mWebView.evaluateJavascript(script, ValueCallback {
           resultCallback.onCallBack(it)
       })
    }

    override fun canGoBack(): Boolean {
     return  mWebView.canGoBack()
    }

    override fun goBack() {
       mWebView.goBack()
    }

    override fun onResume() {
       mWebView.onResume()
    }

    override fun onPause() {
       mWebView.onPause()
    }


    /**
     * 清理数据，防止内存泄漏
     */
    private fun cleanListener(){
        if (mJsDialogListener != null){
            mJsDialogListener = null
        }

        if (mJavascriptInterface != null){
            mJavascriptInterface = null
        }

        if (mStateListener != null){
            mStateListener = null
        }


        if (mInterceptListener != null){
            mInterceptListener = null
        }


        if (mWebViewClient != null){
            mWebViewClient = null
        }

        if (mWebChromeClient != null){
            mWebChromeClient = null
        }

    }

    override fun onDestroyView() {
        cleanListener()

        mWebView.visibility = GONE
        mWebView.stopLoading()
        // 退出时调用此方法，移除绑定的服务，否则某些特定系统会报错
        mWebView.settings.javaScriptEnabled = false
        mWebView.clearHistory()
        mWebView.removeAllViews()
        mWebView.destroy()
    }

    override fun onBackPressed(): Boolean {
        return if (mWebView.canGoBack()) {
            mWebView.goBack()
            true
        } else {
            false
        }
    }
}